#ifdef RT_USE_OLD_CONN_WRAP

#include "RtBase.h"
#include "RtCnRlbTcp.h"
#include "RtTrace.h"
#if !defined (_NEW_PROTO_TP)

///////////////////////////////////////////
//class CRlbConnTCPClient
///////////////////////////////////////////
CRlbConnTCPClient::CRlbConnTCPClient(DWORD dwSendBuffSize) : CRtCnConn(dwSendBuffSize)
{
	m_nUngetDataCnt = 0;

	m_cType = CRtConnectionManager::CTYPE_PDU_RELIABLE;
	m_bPDUNeedACK = dwSendBuffSize == 0 ? FALSE : TRUE;
	m_byConnType = CS_CONN_TYPE_RLB;

	m_bConnectOnceMade = FALSE;

	m_bHandShakeCancelled = FALSE;

	m_pConnConnector = NULL;
	m_byInstanceType = CLIENT_INSTANCE;
	m_dwDisconnTick = 0;
}

CRlbConnTCPClient::~CRlbConnTCPClient()
{
	RT_INFO_TRACE_THIS("CRlbConnTCPClient::~CRlbConnTCPClient()");
	Reset();
}

void CRlbConnTCPClient::Reset()
{
	m_bwctlTimer.Cancel();
	m_nUngetDataCnt = 0;
	CRtCnConn::Reset();
}

void CRlbConnTCPClient::Reset4Reconnect()
{
	m_Timer.Cancel();

	m_nUngetDataCnt = 0;
	
	if(m_pmbLocData)
	{
		m_pmbLocData->DestroyChained();
		m_pmbLocData = NULL;
	}

	if(m_pConnReqPDU)
	{
		m_pConnReqPDU->DestroyChained();
		m_pConnReqPDU = NULL;
	}
	
	m_pITransport = NULL;//IRtTransport *aTrpt with OnConnectIndication() will be different when a new connection is made.

	Reset4Recv();
}

RtResult CRlbConnTCPClient::Disconnect(RtResult aReason)
{
	RT_INFO_TRACE_THIS("CRlbConnTCPClient::Disconnect, m_wStatus="<<m_wStatus<<" m_pITransport="<<m_pITransport<<" aReason="<<aReason);
	m_Timer.Cancel();
	m_ReconnectTimer.Cancel();

	RtResult result = RT_OK;
	if(m_pITransport && m_wStatus != STATUS_UNCONNECTED)
	{
		SendDisconn(aReason);
		result = m_pITransport->Disconnect(aReason);
	}

	SetCurrStatus(STATUS_UNCONNECTED);

	m_pITransportSink = NULL;
	
	if(m_bConnectOnceMade)
		m_bConnectOnceMade = FALSE;
	if (m_pConnConnector)
	{
		m_pConnConnector->GetTPConnector()->CancelConnect();
		m_pConnConnector = NULL;
	}
	m_dwDisconnTick = 0;

	return result;
}

//Client using
void CRlbConnTCPClient::OnRecvDisconn()
{
	//Get reason from Disconn PDU
	CRtCnPduDisconn pdc;
	CRtMessageBlock mb(pdc.GetFixLength());
	pdc.Decode(*m_pmbLocData);

	WORD wReason = pdc.GetReason();
	RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvDisconn(), Normal disconnect, wReason = " << wReason);

	//Waiting for peer do Disconnection
	m_bNormalDisconn = TRUE;
	m_Timer.Cancel();
	m_pITransport->Disconnect(RT_OK);
	m_pITransport = NULL;

	SetCurrStatus(STATUS_UNCONNECTED);
	if(m_pITransportSink)
		m_pITransportSink->OnDisconnect(RT_OK,this);
	//TCP will get OnDisconnect(..) callback later
}

void CRlbConnTCPClient::SetConnConnector(CRlbConnTCPConnector* pConnConnector)
{
	m_pConnConnector = pConnConnector;
};

void CRlbConnTCPClient::CancelHandShake()
{
	//While handshaking
	if(!m_bConnectOnceMade)
	{
		if(m_pITransport)
			m_pITransport->Disconnect((RtResult)RT_OK);
		
		m_bHandShakeCancelled = TRUE;
	}
}

void CRlbConnTCPClient::OnConnectIndication(RtResult aReason, IRtTransport *aTrpt, IRtAcceptorConnectorId *aRequestId)
{
	RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnConnectIndication, aReason="<<aReason<<" aRequestId="<<aRequestId<<" seq4ack="<<m_dwSeq4ACK);
	RT_ASSERTE(m_pConnConnector->GetTPConnector() == aRequestId);

	if(m_bHandShakeCancelled)
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnConnectIndication(), connection has been cancelled.");
		if(aTrpt)
			aTrpt->Disconnect((RtResult)RT_OK);

		return;
	}

	//RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnConnectIndication(), m_pITransport = " << m_pITransport << ", aTrpt = " << aTrpt);

	m_pITransport = aTrpt;

	if(RT_SUCCEEDED(aReason))
	{

		m_pITransport = aTrpt;
		if(aTrpt)
		{
			DWORD dwConnectType = 0;
			m_pITransport->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, &dwConnectType);
			if(dwConnectType & CRtConnectionManager::CTYPE_UDP)
			{
				m_dwMaxBuffLen = 0;
//				if(m_pSendBuf)
					m_SendBuf.SetMaxBufLen(m_dwMaxBuffLen);
			}
		}
		SetCurrStatus(STATUS_CONNECTED);//Physical connection make

		m_pITransport->OpenWithSink(this);

		SendConnReq();

		//m_Timer.schedule(for Timer1);waiting for connect response
		m_Timer.Schedule(this, CRtTimeValue(INTERVAL1, 0));

		//Get Transport type
		DWORD dwTransType = CRtConnectionManager::CTYPE_NONE;

		if(m_pITransport)
			m_pITransport->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, (LPVOID)&dwTransType);

		m_cBaseType = dwTransType;
	}
	else //There are errors, such as timeouted
	{
		if(m_bConnectOnceMade)
		{
			LONGLONG dwCur = GetTickCountEx();
			if(dwCur > m_dwDisconnTick && dwCur - m_dwDisconnTick > CONN_DISCONNECT_TIMEOUT * 1000)
			{
				RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnConnectIndication(), Max time Reconnection timerout");
				if(m_pITransportSink)
					m_pITransportSink->OnDisconnect(aReason, this);
				SetCurrStatus(STATUS_UNCONNECTED);
			}
			else
			{
				m_ReconnectTimer.Schedule(this, CRtTimeValue(3,0), 1);
			}
		}
		else
		{
			//Callback to Upper layer
			m_pConnConnector->GetConnectorSink()->OnConnectIndication(
				aReason, 
				NULL, 
				m_pConnConnector.Get());
			SetCurrStatus(STATUS_UNCONNECTED);
		}
	}
}

void CRlbConnTCPClient::OnDisconnect(RtResult aReason,	IRtTransport *aTrptId)
{
	RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnDisconnect, aReason="<<aReason);
	RT_ASSERTE(m_pITransport == aTrptId);
	if(m_pmbRecData)
	{
		m_pmbRecData->DestroyChained();
		m_pmbRecData = NULL;
	}
	
	//Stop any action of sending
	m_Timer.Cancel();

	m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR);

	if(aReason == RT_ERROR_NETWORK_SOCKET_BIND_ERROR ||
		aReason == RT_ERROR_NETWORK_CONNECT_ERROR ||
		aReason == RT_ERROR_NETWORK_CONNECT_TIMEOUT ||
		aReason == RT_ERROR_NETWORK_CONNECTION_RECONNECT_FAILED)
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnDisconnect(), None Reconnection Disconnect");

		SetCurrStatus(STATUS_UNCONNECTED);

		//Callback ITcpRlbConnSink::OnDisconnect(Reason);
		if(m_pITransportSink)
			m_pITransportSink->OnDisconnect(aReason, this);
	}
	else
	{
		if(m_bNormalDisconn)
		{
			RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnDisconnect(), After recv DisconnPDU");
			
			if(m_pITransportSink)
				m_pITransportSink->OnDisconnect(aReason, this);
			
			return;
		}
		
		if(m_bConnectOnceMade )
		{
			RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnDisconnect(), Need Reconnection");

			LONGLONG dwCur = GetTickCountEx();
			if(m_dwDisconnTick == 0)
				m_dwDisconnTick = dwCur;
			if(dwCur > m_dwDisconnTick && dwCur - m_dwDisconnTick > (CONN_DISCONNECT_TIMEOUT + 10) * 1000)
			{
				RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnDisconnect(), Max time Reconnection timerout");
				if(m_pITransportSink)
					m_pITransportSink->OnDisconnect(aReason, this);
				SetCurrStatus(STATUS_UNCONNECTED);
			}
			else
			{
				m_ReconnectTimer.Schedule(this, CRtTimeValue(3,0), 1);
				SetCurrStatus(STATUS_NEED_RECONNECT);
			}
		}
		else
		{
			m_pConnConnector->GetConnectorSink()->OnConnectIndication(
				aReason, 
				NULL, 
				m_pConnConnector.Get());
			SetCurrStatus(STATUS_UNCONNECTED);
		}
	}
}
	
void CRlbConnTCPClient::OnTimer(CRtTimerWrapper* aId)
{
	if(aId == &m_bwctlTimer)
	{
		if(m_dwCurrentBW > 0 && GetCurrStatus() == STATUS_DATA_CAN_SEND)
		{
			m_dwTotalSendinSec = 0;
			SendDataFromSendBuf();
		}
		return ;
	}
	if(aId == &m_ReconnectTimer)
	{
		Reconnect();
		return;
	}
	if(m_wStatus == STATUS_CONNECTED)//For Timer1 of waiting for ConnResp 
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnTimer(), haven't recv ConnResp PDU.");
		
		if(m_pConnReqPDU)
		{
			m_pConnReqPDU->DestroyChained();
			m_pConnReqPDU = NULL;
		}
		
		m_Timer.Cancel();//Cancel Timer1
		
		if(m_pITransport.Get())
			m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_TIMEOUT);
		
		SetCurrStatus(STATUS_UNCONNECTED);
		
		//Callback to Upper layer
		if(m_bConnectOnceMade) //May be reconnection case
		{
			if(m_pITransportSink)
				m_pITransportSink->OnDisconnect(
				(RtResult)RT_ERROR_NETWORK_CONNECT_TIMEOUT, 
				this);
		}
		else
		{
			//Callback to Upper layer
			m_pConnConnector->GetConnectorSink()->OnConnectIndication(
				(RtResult)RT_ERROR_NETWORK_CONNECT_TIMEOUT, 
				NULL, 
				m_pConnConnector.Get());
		}
	}
	else if(m_wStatus == STATUS_DATA_CAN_SEND)//For Timer2, Send & Check for Keep Alive PDU
	{
		if (!m_isDataSent)
			SendKeepAlive();
		else
			m_isDataSent = FALSE;

		if (!m_isDataReceived)
		{
			m_continuousIdleTime += m_keepAliveInterval;
			if (m_continuousIdleTime>=SERVER_UNAVAIL_TIMEOUT)
			{
				RT_WARNING_TRACE_THIS("CRlbConnTCPClient::OnTimer, connection idle timeout! time="<<m_continuousIdleTime);

				m_Timer.Cancel();//Cancel Timer2
				
				SetCurrStatus(STATUS_UNCONNECTED);
				
				m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR);
				
				//Callback 
				if(m_pITransportSink)
					m_pITransportSink->OnDisconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR, this);
			}
		}
		else
		{
			m_continuousIdleTime = 0;
			m_isDataReceived = FALSE;
		}
	}
}
	
void CRlbConnTCPClient::Reconnect()
{
	RT_INFO_TRACE_THIS("CRlbConnTCPClient::Reconnect()");
	
	if(m_wStatus == STATUS_CONNECTED || m_wStatus == STATUS_DATA_CAN_SEND)
		if(m_pITransport)//TP layer is available
			m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECTION_RECONNECT);
		else
			RT_INFO_TRACE_THIS("CRlbConnTCPClient::Reconnect(), Need Disconnect, but TP transport is not available !");
		
	Reset4Reconnect();
	SetCurrStatus(STATUS_NEED_RECONNECT);

	//Waiting for OnConnectIndication(...) call back
	m_pConnConnector->GetTPConnector()->CancelConnect();

	CRtTimeValue tvTimeOut(TIMEOUT_FOR_CONNECTION);
	m_pConnConnector->GetTPConnector()->AsycConnect(
		this, 
		m_pConnConnector->GetPeerAddr(), 
		&tvTimeOut);
}

void CRlbConnTCPClient::OnRecvConnResp()
{
	m_dwDisconnTick = 0;
	m_Timer.Cancel();

	if(m_bHandShakeCancelled)//do nothing
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvConnResp(), connection has been cancelled.");
		if(m_pITransport)
			m_pITransport->Disconnect((RtResult)RT_OK);
		
		return;
	}

	//Get the channel number from ConnRespPDU
	CRtCnPduConnReqResp presp;
	presp.Decode(*m_pmbLocData);
	WORD wChannel = presp.GetConTag();
	BYTE byConnType = presp.GetConnType();

	if(byConnType != m_byConnType)//Wrong type connection
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvConnResp(), Wrong connection type self type = " << m_byConnType <<
			" Response type = " << byConnType);
		Disconnect((RtResult)RT_ERROR_NETWORK_CONNECTION_WRONG_TYPE);
		
		if(m_bConnectOnceMade) 
		{
			//RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvConnResp(), OnDisconnect() to upper layer");
			if(m_pITransportSink)
				m_pITransportSink->OnDisconnect(
				(RtResult)RT_ERROR_NETWORK_CONNECTION_WRONG_TYPE, 
				this);
		}
		else
		{
			//RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvConnResp(), OnConnectIndication() to upper layer");
			//Callback to Upper layer
			m_pConnConnector->GetConnectorSink()->OnConnectIndication(
				(RtResult)RT_ERROR_NETWORK_CONNECTION_WRONG_TYPE, 
				NULL, 
				m_pConnConnector.Get());
		}
		
		SetCurrStatus(STATUS_UNCONNECTED);
		return;
	}

	RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvConnResp, m_wChannel="<<m_wChannel<<" wChannel="<<presp.GetConTag()<<" trpt="<<m_pITransport.Get());
	
	//Not a Reconnection case
	if(m_wLastStatus == STATUS_UNCONNECTED && m_wStatus == STATUS_CONNECTED)
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvConnResp, Not a Reconnection case");

		m_wChannel = wChannel;
		//Callback ITcpRlbConnSink::OnConnect(..),Indicate upper layer can send data now.
		SetCurrStatus(STATUS_DATA_CAN_SEND);
		m_bConnectOnceMade = TRUE;
		m_pConnConnector->GetConnectorSink()->OnConnectIndication(
			(RtResult)RT_OK, 
			this, 
			m_pConnConnector.Get());
		m_bwctlTimer.Schedule(this,CRtTimeValue(1,0));
	}
	else if(m_wLastStatus == STATUS_NEED_RECONNECT && m_wStatus == STATUS_CONNECTED)	//Reconnection case
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPClient::OnRecvConnResp, Reconnection case");

		//Reconnection, need to Do ACK. 
		if(m_dwMaxBuffLen != 0 && m_SendBuf.DoReconnACK(presp.GetACK()) == -1)//Reconnection failed, wish point must be lost
		{
			if(m_pITransport.Get())
				m_pITransport->Disconnect(
				(RtResult)RT_ERROR_NETWORK_CONNECTION_RECONNECT_FAILED);

			if(m_pITransportSink)
				m_pITransportSink->OnDisconnect(
				(RtResult)RT_ERROR_NETWORK_CONNECTION_RECONNECT_FAILED, 
				this);
			SetCurrStatus(STATUS_UNCONNECTED);
			return;
		}
		SetCurrStatus(STATUS_DATA_CAN_SEND);
		m_isDataSent = FALSE;
		if(m_wChannel != 0)//Handshake was once made 
		{
			RT_ASSERTE(m_wChannel == wChannel);//Must equal!
		}
		if(m_dwMaxBuffLen != 0)
			SendDataFromSendBuf();

		if(m_pITransportSink)
			m_pITransportSink->OnSend(this);
	}
	
	//Destroy Connection Request PDU in m_pConnReqPDU
	if(m_pConnReqPDU)
	{
		m_pConnReqPDU->DestroyChained();
		m_pConnReqPDU = NULL;
	}
	
	//Re-schedule the Timer1 switch to Timer2;
	LONG lKAInterval = (LONG)m_keepAliveInterval;
	m_Timer.Schedule(this, CRtTimeValue(lKAInterval, 0));
}

RtResult CRlbConnTCPClient::GetOption(
		DWORD aCommand, 
		LPVOID aArg)
{
	RtResult rv = RT_ERROR_NOT_AVAILABLE;

	switch(aCommand)
	{
	case RT_OPT_TRANSPORT_TRAN_TYPE:

		if(m_pITransport)
		{
			DWORD dwTransType;

			rv = m_pITransport->GetOption(
				RT_OPT_TRANSPORT_TRAN_TYPE, 
				(LPVOID)&dwTransType);

			if(RT_SUCCEEDED(rv))
			{
				*(static_cast<CRtConnectionManager::CType*>(aArg)) 
				= CRtConnectionManager::CTYPE_PDU_RELIABLE | dwTransType;

				rv = RT_OK;
			}
		}
			
		return rv;
		
	default:
		return CRtCnConn::GetOption(aCommand, aArg);
	}
}
///////////////////////////////////////////
//class CRlbConnTCPServer
///////////////////////////////////////////
CRlbConnTCPServer::CRlbConnTCPServer(DWORD dwSendBuffSize) : CRtCnConn(dwSendBuffSize)
{
	m_pSvrList = NULL;
	m_pConnAcceptor = NULL;

//	m_disconn_timestamp = CRtTimeValue::GetTimeOfDay();

	m_cType = CRtConnectionManager::CTYPE_PDU_RELIABLE;
	m_bPDUNeedACK = dwSendBuffSize == 0 ? FALSE : TRUE;
	m_byConnType = CS_CONN_TYPE_RLB;
	m_byInstanceType = SERVER_INSTANCE;
	m_ReleaseTimer.Schedule(this,CRtTimeValue(CONN_DISCONNECT_TIMEOUT,0), 1);
}

CRlbConnTCPServer::~CRlbConnTCPServer()
{
	RT_INFO_TRACE_THIS("CRlbConnTCPServer::~CRlbConnTCPServer, m_wStatus="<<m_wStatus);
	TryOnDisconnIndicate();
}

void CRlbConnTCPServer::TryOnDisconnIndicate()
{
	m_Timer.Cancel();
	m_bwctlTimer.Cancel();
	if(m_wStatus == STATUS_NEED_RECONNECT)//Timeouted for Reconnection coming
	{
		m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR);
		SetCurrStatus(STATUS_UNCONNECTED);
		if(m_pITransportSink)
			m_pITransportSink->OnDisconnect(
			(RtResult)RT_ERROR_NETWORK_CONNECT_ERROR, 
			this);
	}

	Reset();
}

void CRlbConnTCPServer::Reset()
{
	m_pSvrList = NULL;
	m_pConnAcceptor = NULL;

	//m_disconn_timestamp = CRtTimeValue::GetTimeOfDay();

	CRtCnConn::Reset();
}

RtResult CRlbConnTCPServer::Disconnect(RtResult aReason)
{
	RT_INFO_TRACE_THIS("CRlbConnTCPServer::Disconnect, m_wStatus="<<m_wStatus<<" m_pITransport="<<m_pITransport<<" aReason="<<aReason);
	CRtAutoPtr<CRlbConnTCPServer> pTmpSvr(this);
	m_Timer.Cancel();
	m_ReleaseTimer.Cancel();
	
	RtResult result = RT_OK;

	if(m_pITransport.Get() && m_wStatus != STATUS_UNCONNECTED)
	{
		SendDisconn(aReason);
		result = m_pITransport->Disconnect(aReason);
	}
	m_pITransport = NULL;

	m_pITransportSink = NULL;
	if(m_wStatus != STATUS_UNCONNECTED)
	{
		RT_ASSERTE(m_pSvrList);
		m_pSvrList->RemoveServer(m_wChannel);
		SetCurrStatus(STATUS_UNCONNECTED);
	}
	return result;
}

void CRlbConnTCPServer::OnConnectIndication(
											RtResult aReason,
											IRtTransport *aTrpt,
											IRtAcceptorConnectorId *aRequestId)
{
	//RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnConnectIndication, aTrpt="<<aTrpt);
	//RT_ASSERTE(m_pConnAcceptor->GetTPAcceptor() == aRequestId);
	RT_ASSERTE(aTrpt);

	m_pITransport = aTrpt;
	aTrpt->OpenWithSink(this);
	if(aTrpt)
	{
		DWORD dwConnectType = 0;
		m_pITransport->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, &dwConnectType);
		if(dwConnectType & CRtConnectionManager::CTYPE_UDP)
		{
			m_dwMaxBuffLen = 0;
//			if(m_pSendBuf)
				m_SendBuf.SetMaxBufLen(m_dwMaxBuffLen);
		}
	}

	SetCurrStatus(STATUS_CONNECTED);

	//Get Transport type
	DWORD dwTransType;

	m_pITransport->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, (LPVOID)&dwTransType);
	m_cBaseType = dwTransType;
}

void CRlbConnTCPServer::OnDisconnect(RtResult aReason,	IRtTransport *aTrptId)
{
	RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnDisconnect, aReason="<<aReason);
	if(m_pmbRecData)
	{
		m_pmbRecData->DestroyChained();
		m_pmbRecData = NULL;
	}
	//RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnDisconnect(), aReason = " << aReason << ", aTrptId = " << aTrptId<<", m_wStatus="<<m_wStatus);
	if(m_pITransport != aTrptId)
	{
		RT_ERROR_TRACE_THIS("CRlbConnTCPServer::OnDisconnect(), not match m_pITransport = " << m_pITransport << ", aTrptId = " << aTrptId);
		return;
	}

	CRtAutoPtr<CRlbConnTCPServer> pTmpSvr(this);
	m_Timer.Cancel();
	m_ReleaseTimer.Cancel();
	
	if(m_pITransport)
		m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR);

	
	if(m_bNormalDisconn/* || m_dwMaxBuffLen == 0 for reliable TCP but buffer size is 0*/)//On received DisconnPDU
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnDisconnect(), Normal Disconnect, m_pITransportSink="<<m_pITransportSink);
		SetCurrStatus(STATUS_UNCONNECTED);

		if(m_pITransportSink)
			m_pITransportSink->OnDisconnect(aReason, this);//Network error, Callback to Upper layer
		
		RT_ASSERTE(m_pSvrList);
		m_pSvrList->RemoveServer(m_wChannel);
		//Waiting for a short time to be Removed
		/*m_disconn_timestamp = 
			CRtTimeValue::GetTimeOfDay() - CRtTimeValue(SERVER_NORMAL_DISCONN_TIMEOUT, 0);*/

		return;
	}

	if(aReason == RT_ERROR_NETWORK_SOCKET_BIND_ERROR ||
		aReason == RT_ERROR_NETWORK_CONNECT_ERROR ||
		aReason == RT_ERROR_NETWORK_CONNECT_TIMEOUT)
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnDisconnect(), Network error Disconnect, m_pITransportSink="<<m_pITransportSink);

		SetCurrStatus(STATUS_UNCONNECTED);
		
		if(m_pITransportSink)
			m_pITransportSink->OnDisconnect(aReason, this);//Network error, Callback to Upper layer
		RT_ASSERTE(m_pSvrList);
		m_pSvrList->RemoveServer(m_wChannel);
	}
	else //MAY caused by Reconnection
	{
		//m_ReleaseTimer.Cancel();
//		RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnDisconnect(), May Reconnection Disconnect");
		if(m_wStatus == STATUS_DATA_CAN_SEND)
		{
			Reset4ReconnComing();
			RT_ASSERTE(m_pSvrList);
			//m_pSvrList->AddServer(this, FALSE);
			SetCurrStatus(STATUS_NEED_RECONNECT);
			m_ReleaseTimer.Schedule(this,CRtTimeValue(CONN_DISCONNECT_TIMEOUT,0), 1);
		}
		else
		{
			SetCurrStatus(STATUS_UNCONNECTED);
			RT_ASSERTE(m_pSvrList);
			if(m_pITransportSink)
				m_pITransportSink->OnDisconnect(aReason, this);//Network error, Callback to Upper layer
			m_pSvrList->RemoveServer(m_wChannel);
		}			
	}
}

void CRlbConnTCPServer::Reset4ReconnComing()
{
	m_dwCnt4JudgeACK = 0;
// 	m_dwLastRecvTick = GetTickCountEx();
	m_continuousIdleTime = 0;
	m_isDataReceived = FALSE;

	if(m_pmbLocData)
	{
		m_pmbLocData->DestroyChained();
		m_pmbLocData = NULL;
	}

	Reset4Recv();
}

void CRlbConnTCPServer::OnTimer(CRtTimerWrapper* aId)
{
	if(aId == &m_bwctlTimer)
	{
		if(m_dwCurrentBW > 0 && GetCurrStatus() == STATUS_DATA_CAN_SEND)
		{
			m_dwTotalSendinSec = 0;
			SendDataFromSendBuf();
		}
		return ;
	}
	//Only Send Keep Alive PDU
	if(aId == &m_ReleaseTimer)
	{
		CRtAutoPtr<CRlbConnTCPServer> myself(this);
		RT_ASSERTE(m_pSvrList);
		SetCurrStatus(STATUS_UNCONNECTED);
		if(m_pITransport)
			m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR);
		if(m_pITransportSink)
			m_pITransportSink->OnDisconnect(RT_ERROR_NETWORK_CONNECT_TIMEOUT, this);//Network error, Callback to Upper layer
		m_pSvrList->RemoveServer(m_wChannel);
		return;
	}

	if(m_wStatus == STATUS_DATA_CAN_SEND)
	{
		if (!m_isDataSent)
			SendKeepAlive();
		else
			m_isDataSent = FALSE;

		if (!m_isDataReceived)
		{
			m_continuousIdleTime += m_keepAliveInterval;
			if (m_continuousIdleTime>=SERVER_UNAVAIL_TIMEOUT)
			{
				RT_WARNING_TRACE_THIS("CRlbConnTCPServer::OnTimer, connection idle timeout! time="<<m_continuousIdleTime);

				m_Timer.Cancel();//Cancel Timer2

				CRtAutoPtr<CRlbConnTCPServer> myself(this);
				
				SetCurrStatus(STATUS_UNCONNECTED);
				
				m_pITransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR);
				//Callback 
				if(m_pITransportSink)
					m_pITransportSink->OnDisconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR, this);
				SetCurrStatus(STATUS_UNCONNECTED);
				m_pITransportSink = NULL;
				m_pSvrList->RemoveServer(m_wChannel);
			}
		}
		else
		{
			m_continuousIdleTime = 0;
			m_isDataReceived = FALSE;
		}
	}
}

void CRlbConnTCPServer::OnRecvConnReq(CRtCnPduConnReqResp& preq)
{
	CRtAutoPtr<CRlbConnTCPServer>	myself(this);
	m_ReleaseTimer.Cancel();

	WORD wChannel = preq.GetConTag();
	BYTE byConnType = preq.GetConnType();
	
	if(byConnType != m_byConnType)//Wrong Connection type
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnRecvConnReq(), Wrong Connection type");
		SendConnResp();//Send back with wrong type indication

		Disconnect(RT_ERROR_FAILURE);

		return;
	}

	if(wChannel == 0)//New connection
	{
		RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnRecvConnReq(), wChannel == 0, New connection coming");

		//Whole new connection comes, Callback to Upper layer
		if(m_wLastStatus == STATUS_UNCONNECTED && m_wStatus == STATUS_CONNECTED)//Not a Reconnection case
		{
			//Callback to Upper layer
			m_pConnAcceptor->GetAcceptorSink()->OnConnectIndication(
				(RtResult)RT_OK, 
				this, 
				m_pConnAcceptor.Get());
			m_pSvrList->AddServer(this);
			SetCurrStatus(STATUS_DATA_CAN_SEND);
			LONG lKAInterval = (LONG)m_keepAliveInterval;
			m_Timer.Schedule(this, CRtTimeValue(lKAInterval, 0));
		}

		SendConnResp();
	}
	else if(wChannel > 0)//Reconnection
	{
		if(m_wChannel == wChannel)//Must be resend by Client, I'v already get it before
			return;

		CRtAutoPtr<CRlbConnTCPServer> pSvrOld = m_pSvrList->GetServer(wChannel);

		RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnRecvConnReq, m_wChannel="<<m_wChannel<<" wChannel="<<wChannel<<" pSvrOld="<<pSvrOld.Get());

		if(pSvrOld.Get() == NULL)//pSvrOld had been removed because of unavailable timeout
		{
			RT_INFO_TRACE_THIS("CRlbConnTCPServer::OnRecvConnReq(), pSvrOld had been removed because of unavailable timeout or server restarted");
			IRtTransportSink* sink = m_pITransportSink;
			Disconnect(RT_ERROR_NETWORK_CONNECTION_RECONNECT_FAILED);
			if(sink)
				sink->OnDisconnect(RT_ERROR_NETWORK_CONNECTION_RECONNECT_FAILED, this);	
			return;
		}

		//Else, SvrOld can be found
		pSvrOld->Reset4ReconnComing();
		
		//Reconnection, need to Do ACK. 
		if(m_dwMaxBuffLen != 0 && pSvrOld->m_SendBuf.DoReconnACK(preq.GetACK()) == -1)//Reconnection failed, wish point must be lost
		{
			RT_WARNING_TRACE_THIS("CRlbConnTCPServer::OnRecvConnReq, Reconnection failed!");
			if(pSvrOld->GetSink())
				pSvrOld->GetSink()->OnDisconnect(
				(RtResult)RT_ERROR_NETWORK_CONNECTION_RECONNECT_FAILED, 
				pSvrOld.Get());
			
			pSvrOld->SetCurrStatus(STATUS_UNCONNECTED);
			m_pSvrList->RemoveServer(pSvrOld->GetChannel());	
			Disconnect(RT_ERROR_NETWORK_CONNECTION_RECONNECT_FAILED);
			return;
		}
		pSvrOld->Attach(this);//Attach my m_pITransport to the old
	}
}

void CRlbConnTCPServer::OnRecvConnReq()
{
	//Get wChannel from PDU
	CRtCnPduConnReqResp preq;
	preq.Decode(*m_pmbLocData);
	OnRecvConnReq(preq);
}

void CRlbConnTCPServer::Attach(CRlbConnTCPServer* pSvr)
{
	RT_INFO_TRACE_THIS("CRlbConnTCPServer::Attach, m_wChannel="<<m_wChannel<<" pSvr->m_wChannel="<<pSvr->m_wChannel<<" seq4ack="<<m_dwSeq4ACK);
	m_ReleaseTimer.Cancel();
	if(m_pITransport)
	{
// 		RT_WARNING_TRACE_THIS("CRlbConnTCPServer::Attach, trpt not null. trpt="<<m_pITransport.Get()<<" pSvr="<<pSvr);
// 		SendDisconn(RT_OK);
		m_pITransport->Disconnect(RT_OK);
		m_pITransport = NULL;
		if(m_pmbLocData)
		{
			m_pmbLocData->DestroyChained();
			m_pmbLocData = NULL;
		}
	}
	
	m_pITransport = pSvr->m_pITransport;
	pSvr->m_pITransport = NULL;
	m_pITransport->OpenWithSink(this);
	SetCurrStatus(STATUS_DATA_CAN_SEND);
	m_isDataSent = FALSE;
	SendConnResp();
	if(m_dwMaxBuffLen > 0 )
	{
		SendDataFromSendBuf();
	}

	if(m_pITransportSink)
		m_pITransportSink->OnSend(this);
	LONG lKAInterval = (LONG)m_keepAliveInterval;
	m_Timer.Schedule(this, CRtTimeValue(lKAInterval, 0));
}

void CRlbConnTCPServer::SetServerList(CRlbConnTCPServerList *pSvrList)
{
	m_pSvrList = pSvrList;
}

void CRlbConnTCPServer::SetConnAcceptor(CRlbConnTCPAcceptor* pConnAcceptor)
{
	m_pConnAcceptor = pConnAcceptor;
}

CRtTimeValue CRlbConnTCPServer::GetDisconnTimestamp()
{
	return m_disconn_timestamp;
}

RtResult CRlbConnTCPServer::GetOption(
		DWORD aCommand, 
		LPVOID aArg)
{
	RtResult rv = RT_ERROR_NOT_AVAILABLE;

	switch(aCommand)
	{
	case RT_OPT_TRANSPORT_TRAN_TYPE:

		if(m_pITransport)
		{
			DWORD dwTransType;

			rv = m_pITransport->GetOption(
				RT_OPT_TRANSPORT_TRAN_TYPE, 
				(LPVOID)&dwTransType);

			if(RT_SUCCEEDED(rv))
			{
				*(static_cast<CRtConnectionManager::CType*>(aArg)) 
				= CRtConnectionManager::CTYPE_PDU_RELIABLE | dwTransType;

				rv = RT_OK;
			}
		}
			
		return rv;
		
	default:
		return CRtCnConn::GetOption(aCommand, aArg);
	}
}

RtResult CRlbConnTCPServer::SetOption(
		DWORD aCommand, 
		LPVOID aArg)
{
	switch(aCommand)
	{
	case CS_OPT_SET_BANDWIDTH:
		{
			DWORD dwCurrentBW = (*static_cast<DWORD*>(aArg));
			if(dwCurrentBW == 0)
			{
				m_bwctlTimer.Cancel();
				m_dwCurrentBW = 0;
				SendDataFromSendBuf();
			}
			else
				m_bwctlTimer.Schedule(this,CRtTimeValue(1,0));
		}
		return CRtCnConn::SetOption(aCommand, aArg);
	default:
		return CRtCnConn::SetOption(aCommand, aArg);
	}
}

#endif

#endif // RT_USE_OLD_CONN_WRAP
